package com.example.springboot.资源访问;

public class XxxHandlerMapping请求处理 {
}
/**
 * 1.SpringMVC功能分析都从  处理器映射
 *      会先 进行原生servlet  和 spring 的servlet
 *      优先匹配原生的，如果能处理 就不经过
 *      spring 的 DispatcherServlet 类的  doDispatch()方法
 *      又因为拦截器再spring的servlet 中  所以不走拦截器等等
 *
 * @see org.springframework.web.servlet.DispatcherServlet
 *    org.springframework.web.servlet.DispatcherServlet-》
 *    doDispatch()
 *    都会先执行  doDispatch()  对请求处理
 *    请求使用哪个 Handler（Controller的方法）处理
 *       会遍历 5个 XxxHandlerMapping
 *       {RequestMappingHandlerMapping@5678}
 *           保存了所有 @RequestMapping  和 handler 的映射规则
 *            (自己写的，有@RequestMapping注解的)
 *       {WelcomePageHandlerMapping@5679}
 *            欢迎页的 HandlerMapping (http://localhost:8080/)
 *             会在找到 (静态资源下的) index.html
 *       {BeanNameUrHandlerMapping@5680}
 *       {RouterFunctionMapping@5681}
 *       {SimpleUrHandlerMapping@5682}
 *
 * 可以自定义 XxxHandlerMapping
 * UnlPathHelper(保存所有路径信息)
 */
/**
 * 编写拦截器  注册到容器中
 * 登录检查
 * 1.配置好拦截器要拦截哪些请求
 * 2.把这些配置放在容器中
 *
 * 拦截器执行的位置
 * 第一次  控制器方法之前
 * 第二次  控制器方法之后
 * 第三次  视图渲染完毕之后
 * interceptor  拦截器
 * ctrl+o  可以快捷添加重写的方法
 *
 * 2、拦截器的三个抽象方法
 * SpringMVC中的拦截器有三个抽象方法:
 * preHandle:控制器方法执行之前执行preHandle,
 *           其boolean类型的返回值表示是否拦截或放行，
 *           返回true为放行，即调用控制器方法;
 *           返回false表示拦截，即不调用控制器方法
 * postHandle:控制器方法执行之后执行postHandle
 * afterCompletion:
 *        处理完视图和模型数据，渲染视图完毕之后执行 afterCompletion()
 *
 * 3、多个拦截器的执行顺序
 * a>若每个拦截器的preHandle()都返回true
 *    此时多个拦截器的执行顺序和拦截器在SpringMVC的配置文件的配置顺序有关:
 *     preHandle()会按照配置的顺序执行，
 *    而postHandle()和afterCompletion()会按照配置的反序执行
 * b>若某个拦截器的preHandle()返回了false
 *     preHandle()返回false和它之前的拦截器的preHandle()都会执行，
 *     postHandle()都不执行，
 *     返回false的拦截器之前的拦截器的 afterCompletion()会执行
 *
 * 多个拦截器的执行顺序： 根据配置顺序  在 HandlerExecutionChain类中
 * 假设3个拦截器  1个spring自带 2个手写的
 * * preHandle   按顺序  进入 applyPreHandle 方法   interceptorIndex   从0开始  循环赋值
 * 		    for (int i = 0; i < this.interceptorList.size(); i++) {
 * 		    	HandlerInterceptor interceptor = this.interceptorList.get(i);
 * 		    	if (!interceptor.preHandle(request, response, this.handler)) {
 * 		    		triggerAfterCompletion(request, response, null);//会进入第三个拦截器
 * 		    		return false;
 *                  }
 * 		    	this.interceptorIndex = i;
 * 		    }
 * 		    return true;
 *
 * * postHandle  按反序 进入 applyPostHandle 方法 从拦截器数组.length-1  到0
 *
 *       for (int i = this.interceptorList.size() - 1; i >= 0; i--) {
 * 	    		HandlerInterceptor interceptor = this.interceptorList.get(i);
 * 	    		interceptor.postHandle(request, response, this.handler, mv);
 *       }
 *
 *
 * * afterCompletion    按反序 进入 triggerAfterCompletion 方法   interceptorIndex   减减   到0
 *       for (int i = this.interceptorIndex; i >= 0; i--) {
 *      			HandlerInterceptor interceptor = this.interceptorList.get(i);
 *      			try {
 *      				interceptor.afterCompletion(request, response, this.handler, ex);
 *               }catch (Throwable ex2) {
 *      				logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);
 *               }
 *        }
 *
 */
/**  2.获取参数处理   配置器
 * 先找XxxHandlerMapping 的第一个
 *    RequestMappingHandlerMapping  存了所有自定义的访问路径
 *    再找到合适的配置器(有以下4个)
 *       {RequestMappingHandlerAdapter@5828}
 *          自己有 @RequestMapping 注解的方法(路径访问)
 *      {HandlerFunctionAdapter@5829}  函数式方法
 *      {HttpRequestHandlerAdapter@5830}
 *      {SimpleControllerHandlerAdapter@5831}
 *   找到后 开始执行合适的配置器
 *    RequestMappingHandlerAdapter//一般都是这个
 *       //执行前  会初始化  参数解析器  确定将要执行的目标方法的每-个参数的值是什么
 *     HandlerMethodArgumentResolver//参数解析器  学习的时候26种  就是参数
 *        XxxMethodArgumentResolver//Xxx就像@PathVariable这样的
 *        确定将要执行的目标方法的每一个参数的值是什么;
 *        增强for循环遍历确定 (当用到此参数解析器的话，会放到缓存里)
 *        SpringMVC 目标方法能写多少种参数类型。取决于参数解析器
 *        在 request 的UnlPathHelper(保存所有路径信息)中 找到对应的信息
 *        遍历所有的 参数 并解析
 *
 *     在进行invokeForRequest()方法 利用反射  执行目标方法
 *     也就是被 RequestMapping 注解的方法
 *
 *     返回值处理器  约15种 XxxMethodReturnValueHandler .
 *     支持哪几种返回值(如 map，Model,ModelAndView，ModelMap等)
 *
 *   执行目标方法后 将所有信息
 *      将所有的数据都放在ModelAndViewContainer;
 *      最后都会遍历  会被放在 request的请求域中
 *      包含要去的页面地址View。还包含Model数据
 *
 */
/**
 * 3.参数返回处理 执行目标方法后执行  返回值处理器
 *    对加了@ResponseBody 的方法的返回值进行处理
 *   返回值处理器  15种 XxxMethodReturnValueHandler .
 *   支持哪几种返回值(如 map，Model,ModelAndView，ModelMap等)
 *   //可以自定义
 *   先遍历 查看是否是异步的  再交给返回值处理器(默认15种)
 *   0 = {ModelAndViewMethodRetumValueHandler@5835} // @5835 会随时变
 *   1 = {ModelMethodProcessor@5836}
 *   2 = {ViewMethodReturnValueHandler@5837}
 *   3 = {ResponseBodyEmitterReturmValueHandler@5838}
 *   4 = {StreamingResponseBodyReturnValueHandler@5839}
 *   5 = {HttpEntityMethodProcessor@5840}
 *   6 = {HttpHeadersReturValueHandler@5841}
 *   7 = {CallableMethodRetumValueHandler@5842}
 *   8 = {DeferredResultMethodRetumValueHandler@5843}
 *   9 = {AsyncTaskMethodReturnValueHandler@5844}
 *   10 = {ModelAttributeMethodProcessor@5845}
 *         @ModelAttribute 注解(类似于) @RequestMapping
 *         不过返回值会保存在隐含的Model里 不进行页面跳转
 *   11 = {RequestResponseBodyMethodProcessor@5846}
 *          有 @ResponseBody 注解的，用这个处理器
 *   12 = {ViewNameMethodReturnValueHandler@5847}
 *         这个会处理那些 跳转和重定向的信息
 *   13 = {MapMethodProcessor@5848}
 *   14 = {ModelAttributeMethodProcessor@5849}
 * ● 1、返回值处理器判断是否支持这种类型返回值 supportsReturnType
 * ● 2、支持了返回值处理器调用 handleReturnValue 进行处理
 * ● 3、RequestResponseBodyMethodProcessor 可以处理返回值标了 @ResponseBody 注解的。
 *   ○ 1.  利用 MessageConverters(消息转换器) 进行处理 将数据写为json
 *     ■ 1、内容协商（浏览器默认会以请求头的方式告诉服务器他能接受什么样的内容类型）
 *          请求头中Accept字段。Http协议中规定的，告诉服务器本客户端可以接收的数据类型。
 *          ● 支持 将对象转为 最佳匹配媒体类型 的converter。调用它进行转化。(请求头 告诉了)
 *     ■ 2、服务器最终根据自己自身的能力，决定服务器能生产出什么样内容类型的数据，
 *          (请求头 告诉了的类型，和服务器能生产的类型，进行匹配 复杂度N*N)
 *     ■ 3、SpringMVC会挨个遍历所有容器底层的 HttpMessageConverter ，看谁能处理？
 *                XxxMessageConverter 接口有5个方法
 *                canRead 是否能读      canWrite 是否能写
 *                getSupportedMediaTypes 获取支持的媒体类型
 *                read  (能读了)读      write(能写了)写
 *           0 = {ByteArrayHttpMessageConverter@6214}           支持Byte类型的
 *           1 = {StringHttpMessageConverter@6221}              支持String
 *           2 = {StringHttpMessageConverter@6222}              支持String
 *           3 = {ResourceHttpMessageConverter@6223}            支持Resource
 *           4 = {ResourceRegionHttpMessageConverter@6224}      支持ResourceRegion
 *           5 = {SourceHttpMessageConverter@6225}
 *              支持DOMSource.class\SAXSource.class\StAXSource.class\StreamSource.class\Source.class
 *           6 = {AllEncompassingFormHttpMessageConverter@6226}   支持MultiValueMap
 *           7 = {MappingJackson2HttpMessageConverter@6227}       支持true
 *           8 = {MappingJackson2HttpMessageConverter@6228}       支持true
 *       当导入xml包的时候 就没了 //9 = {Jaxb2RootElementHttpMessageConverter@6229}      支持支持注解方式xml处理的。
 *           9 = {MappingJackson2XmlHttpMessageConverter@6178}
 *           10 = {MappingJackson2XmlHttpMessageConverter@6179}
 *            当导入了 xml的包的时候  内部写死了 直接加载 9 10
 *       ● 1、得到MappingJackson2HttpMessageConverter可以将对象写为json
 *       ● 2、利用MappingJackson2HttpMessageConverter将对象转为json再写出去。
 *     根据客户端接收能力不同，返回不同媒体类型的数据。
 *
 *      会先判断有没有拦截器给他指定类型 之后
 *       它会根据  浏览器的请求头    获取能接受的数据类型
 *            contentNegotiationManager 内容协商管理器 默认使用基于请求头的策略
 *        再获取能产出的数据类型    进行匹配 复杂度N*N
 *           HeaderContentNegotiationStrategy  确定客户端可以接收的内容类型
 *      把能匹配的  添加在一个数组里   找到最佳匹配 （有转换权重   权重大的优先）经行封装 返回
 *
 *     可以自己配置  详见 com.example.springboot.config.LongMessageConverters
 *
 *    可以开启基于参数的内容协商
 *       如果浏览器  想要自定义 想要什么  就要什么  可以开启基于参数的内容协商 （在配置文件中）
 *       spring:
 *         mvc:
 *           contentnegotiation:
 *             favor-parameter:true  #true  开启 默认false
 *          开启后 他会再得到请求头的内容协商 前     (优先级最高)
 *          获取一个基于参数的内容协商 而且参数是 format  但是只支持 json 和 xml
 *       在网址中加 http://localhost:8080/test/user?format=json
 *       表示返回json数据  优先级最高
 *      在maven里添加一个xml  依赖   如果浏览器的请求头xml优先级高   就会优先转换成xml
 *
 */
/**
 * 4.视图解析原理流程  视图解析器
 *   1、目标方法处理的过程中，所有数据都会被放在 ModelAndViewContainer 里面。
 *      包括数据和视图地址
 *   2、方法的参数是一个自定义类型对象（从请求参数中确定的），
 *      把他重新放在 ModelAndViewContainer
 *   3、任何目标方法执行完成以后都会返回 ModelAndView（数据和视图地址）。
 *   4、processDispatchResult  处理派发结果（页面改如何响应）
 *     ● 1、render(mv, request, response); 进行页面渲染逻辑
 *     ○ 1、根据方法的 String 返回值得到 View 对象【定义了页面的渲染逻辑】
 *           视图解析器
 *          0 = {ContentNegotiatingViewResolver@7053}//这一个包含了一下四个 所以下面的 都没轮到
 *          1 = {BeanNameViewResolver@7054}//是否有String的组件
 *          2 = {ThymeleafViewResolver@7055}//是否可以跳转
 *          3 = {ViewResolverComposite@7056}
 *          4 = {InternalResourceViewResolver@7057}
 *       ■ 1、所有的视图解析器尝试是否能根据当前返回值得到View对象
 *       ■ 2、得到了  redirect:/main.html --> Thymeleaf new RedirectView()
 *            如果ModelAndView里没有View的信息  他会默认一个 当前路径
 *       ■ 3、ContentNegotiationViewResolver 里面包含了下面所有的视图解析器，
 *       ■ 4、view.render(mv.getModelInternal(), request, response);
 *            视图对象调用自定义的render进行页面渲染工作
 *         ● RedirectView 如何渲染【重定向到一个页面】
 *         ● 1、获取目标url地址
 *         ● 2、response.sendRedirect(encodedURL);//使用最原始的
 *
 *
 * 视图解析：
 *   ○ 返回值以 forward: 开始： new InternalResourceView(forwardUrl); -->
 *         转发 request.getRequestDispatcher(path).forward(request, response);
 *   ○ 返回值以 redirect: 开始： new RedirectView() --》 render就是重定向
 *   ○ 返回值是普通字符串： new ThymeleafView（）--->他自己的方式 进行解析
 *
 * 还可以自定义 视图解析器
 *
 */